// Copyright 2017 Baidu Inc. All Rights Reserved.
// Author: Pan Haijun, Gang Chen(chengang12@baidu.com)
//
// This file wrap the socket APIs for http module.

#include "baidu_mbed_soc_wrapper.h"
#include "mbed.h"
#include "TCPSocket.h"
#ifdef TARGET_UNO_91H
#ifdef BAIDU_NO_MAIN_ENTRY
#include "baidu_wifi_ssid_config.h"
#endif
#include "WiFiStackInterface.h"
#else
#include "EthernetInterface.h"
#endif
#include "heap_monitor.h"
#include "baidu_http_client_c.h"
#include "duer_log.h"

extern void* baidu_get_netstack_instance(void);

#ifdef BAIDU_NO_MAIN_ENTRY
int g_baidu_network_connected = 0;
#endif

typedef struct _mbed_sock_hdl {
#ifdef TARGET_UNO_91H
    WiFiStackInterface* p_net_stk;
#else
    EthernetInterface* p_net_stk;
#endif
    TCPSocket* p_socket;
} mbed_sock_hdl;

int mbed_socket_init(void* socket_args) {
    mbed_sock_hdl* p_soc_hdl = NULL;

    DUER_LOGD("mbed_socket_init to create socket\n");

    p_soc_hdl = (mbed_sock_hdl*)MALLOC(sizeof(mbed_sock_hdl), HTTP);
    if (!p_soc_hdl) {
        return (int)NULL;
    }

    memset(p_soc_hdl, 0, sizeof(mbed_sock_hdl));
#ifdef TARGET_UNO_91H
    p_soc_hdl->p_net_stk = (WiFiStackInterface*)baidu_get_netstack_instance();
#else
    p_soc_hdl->p_net_stk = (EthernetInterface*)baidu_get_netstack_instance();
#endif

    if (!p_soc_hdl->p_net_stk) {
        FREE(p_soc_hdl);
        return (int)NULL;
    }
    p_soc_hdl->p_socket = NEW(HTTP) TCPSocket();

    if (!p_soc_hdl->p_socket) {
        FREE(p_soc_hdl);
        return (int)NULL;
    }

#ifdef BAIDU_NO_MAIN_ENTRY
    if (!g_baidu_network_connected) {
#ifdef TARGET_UNO_91H
        if (p_soc_hdl->p_net_stk->connect(BD_NET_STACK_SOC_WIFI_SSID, BD_NET_STACK_SOC_WIFI_PASS,
                                          NSAPI_SECURITY_NONE) == 0) {
#else
        if (p_soc_hdl->p_net_stk->connect() == 0) {
#endif
            const char* ip = p_soc_hdl->p_net_stk->get_ip_address();
            const char* mac = p_soc_hdl->p_net_stk->get_mac_address();
            DUER_LOGD("IP address is: %s\n", ip ? ip : "No IP");
            DUER_LOGD("MAC address is: %s\n", mac ? mac : "No MAC");
            g_baidu_network_connected = 1;
        } else {
            DUER_LOGE("Network initial failed....");
            Thread::wait(osWaitForever);
        }
    }
#endif //end of BAIDU_NO_MAIN_ENTRY
    p_soc_hdl->p_socket->open(p_soc_hdl->p_net_stk);

    return (int)p_soc_hdl;
}

int mbed_socket_open(int socket_handle) {
    mbed_sock_hdl* p_soc_hdl = (mbed_sock_hdl*)socket_handle;

    if (!p_soc_hdl || !p_soc_hdl->p_socket) {
        DUER_LOGE("socket is NULL!\n");
        return -1;
    }

    return p_soc_hdl->p_socket->open(p_soc_hdl->p_net_stk);
}

int mbed_socket_connect(int socket_handle, const char* host, const int port) {
    mbed_sock_hdl* p_soc_hdl = (mbed_sock_hdl*)socket_handle;

    if (!p_soc_hdl || !p_soc_hdl->p_socket) {
        DUER_LOGE("socket is NULL!\n");
        return -1;
    }

    return p_soc_hdl->p_socket->connect(host, (uint16_t)port);
}

void mbed_socket_set_blocking(int socket_handle, int blocking) {
    mbed_sock_hdl* p_soc_hdl = (mbed_sock_hdl*)socket_handle;

    if (!p_soc_hdl || !p_soc_hdl->p_socket) {
        DUER_LOGE("socket is NULL!\n");
        return;
    }

    p_soc_hdl->p_socket->set_blocking(blocking);
}

void mbed_socket_set_timeout(int socket_handle, int timeout) {
    mbed_sock_hdl* p_soc_hdl = (mbed_sock_hdl*)socket_handle;

    if (!p_soc_hdl || !p_soc_hdl->p_socket) {
        DUER_LOGE("socket is NULL!\n");
        return;
    }

    p_soc_hdl->p_socket->set_timeout(timeout);
}

int mbed_socket_recv(int socket_handle, void* data, unsigned size) {
    mbed_sock_hdl* p_soc_hdl = (mbed_sock_hdl*)socket_handle;

    if (!p_soc_hdl || !p_soc_hdl->p_socket) {
        DUER_LOGE("socket is NULL!\n");
        return -1;
    }
    int rs = p_soc_hdl->p_socket->recv(data, size);

    return rs;
}

int mbed_socket_send(int socket_handle, const void* data, unsigned size) {
    mbed_sock_hdl* p_soc_hdl = (mbed_sock_hdl*)socket_handle;

    if (!p_soc_hdl || !p_soc_hdl->p_socket) {
        DUER_LOGE("socket is NULL!\n");
        return -1;
    }

    int rs = p_soc_hdl->p_socket->send(data, size);

    return rs;
}

int mbed_socket_close(int socket_handle) {
    mbed_sock_hdl* p_soc_hdl = (mbed_sock_hdl*)socket_handle;

    if (!p_soc_hdl || !p_soc_hdl->p_socket) {
        DUER_LOGE("socket is NULL!\n");
        return -1;
    }

    int rs = p_soc_hdl->p_socket->close();

    return rs;
}

#if 0
int mbed_socket_stop(int socket_handle) {
    mbed_sock_hdl* p_soc_hdl = (mbed_sock_hdl*)socket_handle;

    if (!p_soc_hdl || !p_soc_hdl->p_socket) {
        DUER_LOGE("socket is NULL!\n");
        return -1;
    }

    int rs = p_soc_hdl->p_socket->stop();

    return rs;
}
#endif

void mbed_socket_destroy(int socket_handle) {
    mbed_sock_hdl* p_soc_hdl = (mbed_sock_hdl*)socket_handle;

    if (!p_soc_hdl || !p_soc_hdl->p_socket || !p_soc_hdl->p_net_stk) {
        DUER_LOGE("socket is NULL!\n");
        return;
    }

    delete p_soc_hdl->p_socket;
    p_soc_hdl->p_socket = NULL;
    FREE(p_soc_hdl);
}

